<?php
class AdminActiveRecord extends CActiveRecord {
	protected $logAttributes = array ('userid' => '^^userid', 'username' => '^^username', 'runtime' => '^^request_time', 'ip' => '^^ip', 'event_type' => '^^event', 'page' => '^^action', 
			'sta' => '^^sta', 'usertype' => '^^usertype', 'request_data' => '^^request_data' );
	protected $logEvents = '';
	
	protected $isMemCachePage = false; // 列表页memcached开关,是否启用memcached缓存，true为打开，false为关闭
	
	protected $pageMemCacheTime = 900; // 列表数据缓存时间,调用getListByPage的时候用到
	protected static $trans=null;
	
	
	/*
	 * memcached缓存版本最大数值，列表页memcached缓存会根据这个版本数决定取那个版本的缓存，
	 * 每当一个模型相关的数据表数据通过该模型的操作函数发生改变时，与此模型相关的列表页缓存版本会增加1，当达到最大版本值时，会重置为1
	 */
	protected $keyVersionMax = 1001;
	
	public function __construct($scenario = 'insert') {
		parent::__construct ( $scenario );
		if ($this->isMemCachePage) {
			$this->attachEventHandler ( 'onAfterChange', array ($this, 'clearPageMem' ) );
		}
	}
	
	/**
	 * 打折信息从后台经工作人员发布，先发后审
	 */
	public function  addConditionOnDis($criteria,$model)
	{
		$arr = Yii::app()->params['dis_table'];
		if(Yii::app()->params['dis_sta'])
		{
			$criteria->addCondition ( '( '.$arr[$model->tableName].' = 1 or ( '.$arr[$model->tableName].' = 0 and admin_publisher>0))' );
		}
		else
		{
			$criteria->addCondition(''.$arr[$model->tableName].' > 0 ');
		}
		return $criteria;
	}
	
	public function scopes() {
		if (Yii::app ()->controller->userType == 1) {
			// 后台用户
			$area_code = Yii::app ()->admin->getStorage ( 'area_code', '101' );
		} else {
			// 前台用户
			$area_code = Yii::app ()->controller->siteAreaCode;
		}
		return array ('areaFilter' => array ('condition' => 'area_code LIKE \'' . $area_code . '%\'' ), 
				'shopAreaFilter' => array ('condition' => 'shop_area_code LIKE \'' . $area_code . '%\'' ) );
	}
	
	/*
	 * 清除与当前模型类有关的在memcached中的key集合，相当于清除了依赖于该key集合的所有缓存
	 */
	public function clearPageMem($event) {
		return $this->updateMemKeyVersion ();
	}
	
	/**
	 * 当数据库改变时触发
	 * 
	 * @param $event CEvent
	 *       	 added by zjx
	 */
	public function onAfterChange($event) {
		$this->raiseEvent ( 'onAfterChange', $event );
	}

    /*
	*当有数据库操作语句执行失败时运行
	*lyh
	*/
    public function onExecSqlFail(){
        isset(Yii::app()->controller->execSqlFail) && Yii::app()->controller->execSqlFail = true;
		//post防重复提交处理,如果有操作类sql执行失败，则不对post重复提交做限制
		if(Yii::app()->request->getIsPostRequest()){
		    if(Yii::app()->controller->userType == 1){
                Yii::app()->admin->setState(Controller::$postLimitKey,'');
	        }
		    elseif(Yii::app()->controller->userType == 2){
                Yii::app()->frontuser->setState(Controller::$postLimitKey,'');
		    }
		}
	}

	/**
	 * 在数据库改变后触发
	 * added by zjx
	 */
	protected function afterChange() {
		if ($this->hasEventHandler ( 'onAfterChange' ))
			$this->onAfterChange ( new CEvent ( $this ) );
	}
	
	public function insert($attributes = null) {
		$flag = parent::insert ( $attributes );
		$this->logging ( $flag );
		if ($flag) {
			$this->afterChange ();
		}
		else{
            $this->onExecSqlFail();
		}
		return $flag;
	}
	/**
	 * 开始事务
	 * @throws Exception
	 */
	public function beginTrans(){
		if(is_null(self::$trans)){
			$this->setDbconnection( 'W');
			self::$trans=$this->getDbConnection()->beginTransaction();
		}else{
			throw new Exception('一个事务正开启，在未执行rollBack或者commint方法之前，不能再开启事务');
		}
	}
	/**
	 * 回滚事务
	 * @throws Exception
	 */
	public function rollBack(){
		if(is_null(self::$trans)){
			throw new Exception('事务还未开启');
		}
		self::$trans->rollback();
		self::$trans=null;
	}
	/**
	 * 提交事务
	 * @throws Exception
	 */
	public function commit(){
		if(is_null(self::$trans)){
			throw new Exception('事务还未开启');
		}
		self::$trans->commit();
		self::$trans=null;
	}	
	public function deleteAllByAttributes($attributes, $condition = '', $params = array()) {
		$flag = parent::deleteAllByAttributes ( $attributes, $condition, $params );
		$this->logging ( $flag );
		if ($flag) {
			$this->afterChange ();
		}
		else{
            $this->onExecSqlFail();
		}
		return $flag;
	}
	
	public function deleteAll($condition = '', $params = array()) {
		$flag = parent::deleteAll ( $condition, $params );
		$this->logging ( $flag );
		if ($flag) {
			$this->afterChange ();
		}
		else{
            $this->onExecSqlFail();
		}
		return $flag;
	}
	
	public function deleteByPk($pk, $condition = '', $params = array()) {
		$flag = parent::deleteByPk ( $pk, $condition, $params );
		$this->logging ( $flag );
		if ($flag) {
			$this->afterChange ();
		}
		else{
            $this->onExecSqlFail();
		}
		return $flag;
	}
	
	public function updateCounters($counters, $condition = '', $params = array()) {
		$flag = parent::updateCounters ( $counters, $condition, $params );
		$this->logging ( $flag );
		if ($flag) {
			$this->afterChange ();
		}
		else{
            $this->onExecSqlFail();
		}
		return $flag;
	}
	
	public function updateAll($attributes, $condition = '', $params = array()) {
		$flag = parent::updateAll ( $attributes, $condition, $params );
		$this->logging ( $flag );
		if ($flag) {
			$this->afterChange ();
		}
		else{
            $this->onExecSqlFail();
		}
		return $flag;
	}
	
	public function updateByPk($pk, $attributes, $condition = '', $params = array()) {
		$flag = parent::updateByPk ( $pk, $attributes, $condition, $params );
		$this->logging ( $flag );
		if ($flag) {
			$this->afterChange ();
		}
		else{
            $this->onExecSqlFail();
		}
		return $flag;
	}
	
	/*
	 * (non-PHPdoc) @see CActiveRecord::saveAttributes()
	 */
	
	public function saveAttributes($attributes) {
		// TODO Auto-generated method stub
		if ($this->validate ( array_keys($attributes) )) {
			$flag = parent::saveAttributes ( $attributes );
			$this->logging ( $flag );
			if ($flag) {
				$this->afterChange ();
			}
		    else{
                $this->onExecSqlFail();
		    }
			return $flag;
		}
		return false;
	
	}
	

	/*
	 * @param int $page 页码,默认为0 @param int $pageSize 每页记录数 默认为15 @param
	 * array/CDbCriteria criteria 查询条件
	 * ,默认是空数组,可以是查询数组，也可以是CDbCriteria对象，不用设置offset和limit这两个属性。具体参考find()说明。默认查询出在所传页码内的所有记录
	 * @param bool $isMemCache 是否启用memcached缓存，true为开启，false为关闭 @return
	 * 格式是array('count'=>,'data'=>array()).count元素为符合查询条件的所有记录总数。data元素为符合条件并在所传页码数内的记录数组
	 *@param int $forceCacheTime 强制缓存时间，默认为false，表示不强制缓存。如果为整数，则表示强制缓存相应的时间，不管数据库的更改状况
	 */
	public function getListByPage($page = 0, $pageSize = 15, $criteria = array(), $isMemCache = true, $forceCacheTime = false, $withCount = true) {
		$oldCriteria = $this->getDbCriteria ();
		if ($criteria instanceof CDbCriteria) {
			$newCriteria = $criteria;
			$newCriteria->mergeWith ( $oldCriteria );
		} else if(is_array($criteria) && count($criteria)>0){
			$newCriteria=clone $oldCriteria;
			$newCriteria->mergeWith ( $criteria );
		} else{
			$newCriteria=$criteria;
		}
		if ($this->isMemCachePage && $isMemCache) {
			$className = strtolower ( get_called_class () );
			$listKey = $this->genListMemKey ( $page, $pageSize, $criteria, $forceCacheTime );
			$return = UtilD::getCache ( $className, $listKey );
			if ($return) {
				return $return;
			}
		}
		
		if ($pageSize > 1 && $withCount) {
			$count = $this->count ( $newCriteria );
		} else { // 处理只读取一条的情况，提高效率
			$count = 1;
		}
		if ($count < 1) {
			$return = array ('count' => 0, 'data' => array () );
		} else {
			if ($page < 1) {
				$page = 0;
			} else {
				$page = $page - 1;
			}
			$offset = $page * $pageSize;
			if ($offset >= $count) {
				$return = array ('count' => $count, 'data' => array () );
			} else {
				if (is_array ( $newCriteria )) {
					$newCriteria ['offset'] = $offset;
					$newCriteria ['limit'] = $pageSize;
				} elseif (is_object ( $criteria )) {
					$newCriteria->offset = $offset;
					$newCriteria->limit = $pageSize;
				}
				$query = $this->findAll ( $newCriteria );
				if (empty ( $query ) || ! $withCount) { // 处理只读取一条或者不需要返回count的情况，提高效率
					$count = 0;
				}
				$return ['count'] = $count;
				$return ['data'] = array ();
				foreach ( $query as $rs ) {
					$return ['data'] [] = $rs->getAttributes ();
				}
			}
		}
		if ($this->isMemCachePage && $isMemCache) {
			// if(UtilD::setCache ( $className, $listKey, $return,
			// $this->pageMemCacheTime )){
			// $this->saveKeyToMemKeySet($listKey);
			// }
			$cacheTime = $forceCacheTime === false ? $this->pageMemCacheTime : $forceCacheTime;
			UtilD::setCache ( $className, $listKey, $return, $cacheTime );
		}
		
		return $return;
	}
	/*
	 * 此方法等同于getListByPage,一般情况下推荐使用getListByPage。此方法只是为了克服Yii的bug而存在
	 * @param int $page 页码,默认为0 @param int $pageSize 每页记录数 默认为15 @param
	 * array/CDbCriteria criteria 查询条件
	 * ,默认是空数组,可以是查询数组，也可以是CDbCriteria对象，不用设置offset和limit这两个属性。具体参考find()说明。默认查询出在所传页码内的所有记录
	 * @param bool $isMemCache 是否启用memcached缓存，true为开启，false为关闭 @return
	 * 格式是array('count'=>,'data'=>array()).count元素为符合查询条件的所有记录总数。data元素为符合条件并在所传页码数内的记录数组
	 */
	public function getListByPage2($page = 0, $pageSize = 15, $criteria = array(), $isMemCache = true) {
		if ($this->isMemCachePage && $isMemCache) {
			$className = strtolower ( get_called_class () );
			$listKey = $this->genListMemKey ( $page, $pageSize, $criteria );
			$return = UtilD::getCache ( $className, $listKey );
			if ($return) {
				return $return;
			}
		}
		
		$count = $this->count ( $criteria );
		if ($count < 1) {
			$return = array ('count' => 0, 'data' => array () );
		} else {
			if ($page < 1) {
				$page = 0;
			} else {
				$page = $page - 1;
			}
			$offset = $page * $pageSize;
			if ($offset >= $count) {
				$return = array ('count' => $count, 'data' => array () );
			} else {
				if (is_array ( $criteria )) {
					$criteria ['offset'] = $offset;
					$criteria ['limit'] = $pageSize;
				} elseif (is_object ( $criteria )) {
					$criteria->offset = $offset;
					$criteria->limit = $pageSize;
				}
				$query = $this->findAll ( $criteria );
				$return ['count'] = $count;
				$return ['data'] = array ();
				foreach ( $query as $rs ) {
					$return ['data'] [] = $rs->getAttributes ();
				}
			}
		}
		if ($this->isMemCachePage && $isMemCache) {
			// if(UtilD::setCache ( $className, $listKey, $return,
			// $this->pageMemCacheTime )){
			// $this->saveKeyToMemKeySet($listKey);
			// }
			UtilD::setCache ( $className, $listKey, $return, $this->pageMemCacheTime );
		}

		return $return;
	}

	/*
	 * add by wc 2012-2-8 only for notice/trend/vote/adpostion/promptPostion
	 * list @param int $page 页码,默认为0 @param int $pageSize 每页记录数 默认为15 @param
	 * array/CDbCriteria criteria 查询条件
	 * ,默认是空数组,可以是查询数组，也可以是CDbCriteria对象，不用设置offset和limit这两个属性。具体参考find()说明。默认查询出在所传页码内的所有记录
	 * @param bool $isMemCache 是否启用memcached缓存，true为开启，false为关闭 @return
	 * 格式是array('count'=>,'data'=>array()).count元素为符合查询条件的所有记录总数。data元素为符合条件并在所传页码数内的记录数组
	 */
	public function getListByPageCop($page = 0, $pageSize = 15, $criteria = array(), $isMemCache = true) {
		$oldCriteria = $oldCriteria2 = $this->getDbCriteria ();
		$oldCriteria2->mergeWith ( $criteria );
		if ($this->isMemCachePage && $isMemCache) {
			$className = strtolower ( get_called_class () );
			// $keySet = $this->getMemVersion();
			$listKey = $this->genListMemKey ( $page, $pageSize, $oldCriteria2 );
			// echo $listKey;
			// if(is_array($keySet) && in_array($listKey,$keySet)){
			// if($keySet){
			$return = UtilD::getCache ( $className, $listKey );
			if ($return) {
				return $return;
			}
			// }
		}
		
		$count = $this->count ( $criteria );
		$this->setDbCriteria ( $oldCriteria );
		if ($count < 1) {
			$return = array ('count' => 0, 'data' => array () );
		} else {
			if ($page < 1) {
				$page = 0;
			} else {
				$page = $page - 1;
			}
			$offset = $page * $pageSize;
			if ($offset >= $count) {
				$return = array ('count' => $count, 'data' => array () );
			} else {
				if (is_array ( $criteria )) {
					$criteria ['offset'] = $offset;
					$criteria ['limit'] = $pageSize;
				} elseif (is_object ( $criteria )) {
					$criteria->offset = $offset;
					$criteria->limit = $pageSize;
				}
				$query = $this->findAll ( $criteria );
				$return ['count'] = $count;
				$return ['data'] = array ();
				foreach ( $query as $rs ) {
					$return ['data'] [] = $rs->getAttributes ();
				}
			}
		}
		$this->setDbCriteria ( NULL );
		if ($this->isMemCachePage && $isMemCache) {
			if (UtilD::setCache ( $className, $listKey, $return, $this->pageMemCacheTime )) {
				// $this->saveKeyToMemKeySet($listKey);
			}
		}
		return $return;
	}
	/*
	 * 产生在memcached中缓存的列表页结果集对应的key
	 *@param int $forceCacheTime 强制缓存时间，默认为false，表示不强制缓存。如果为整数，则表示强制缓存相应的时间，不管数据库的更改状况
	 */
	public function genListMemKey($page, $pageSize, $criteria = array(), $forceCacheTime = false) {
		$key = 'cache_list';
		$className = strtolower ( get_called_class () );
		$key .= '_' . $className;
		if($forceCacheTime === false){
		    $version = $this->getMemVersion ();
		    $lastVersion = $version --;
		    $key .= '_version' . $version;
		}
		/*
		 * $condition = ''; if(is_array($criteria) &&
		 * isset($criteria['condition']) && $criteria['condition']){ $condition
		 * .= $criteria['condition']; if(isset($criteria['params']) &&
		 * !empty($criteria['params'])){ $condition .=
		 * '_'.serialize($criteria['params']); } if(isset($condition['order'])){
		 * $condition .= $condition['order']; } $key .= '_'.md5($condition); }
		 * elseif(is_object($criteria) && $criteria->condition){ $condition .=
		 * $criteria->condition; if(isset($criteria->params) &&
		 * !empty($criteria->params)){ $condition .=
		 * '_'.serialize($criteria->params); } if(){ } $key .=
		 * '_'.md5($condition); }
		 */
		$key .= '_' . md5 ( serialize ( $criteria ) );
		$key .= '_' . $pageSize . '_' . $page;
		if($forceCacheTime === false){
		    $lastKey = str_replace ( '_version' . $version, '_version' . $lastVersion, $key );
		    $this->removePageMem ( $lastKey ); // 清理前一个版本的缓存
		}
		return $key;
	}
	
	/*
	 * 获取当前模型对象所对应的模型类在memcached中的key集合
	 */
	public function getMemVersion() {
		$className = strtolower ( get_called_class () );
		$key = 'keyversion_' . $className;
		$version = UtilD::getCache ( $className, $key );
		if (! $version) {
			// $this->updateMemKeyVersion();
			// $version = UtilD::getCache ( $className, $key );
			$version = 1;
			UtilD::setCache ( $className, $key, $version, 3600 );
		}
		return $version;
	}
	
	/*
	 * 清除当前模型对象所对应的模型类在memcached中的key集合,相当于清除了依赖于该key缓存集合的所有缓存
	 */
	public function updateMemKeyVersion() {
		$className = strtolower ( get_called_class () );
		$currentKey = 'keyversion_' . $className;
		$clearKeys = array ($className => $currentKey );
		if (isset ( $this->mem_relates ) && is_array ( $this->mem_relates ) && count ( $this->mem_relates )) {
			foreach ( $this->mem_relates as $k => $v ) {
				if ($v) {
					$k = strtolower ( $k );
					$clearKeys [$k] = 'keyversion_' . $k;
				}
			}
		}
		foreach ( $clearKeys as $key => $memkey ) {
			// $className = substr($key,11);
			$version = UtilD::getCache ( $key, $memkey );
			if ($version) {
				$version = intval ( $version );
				if ($version < $this->keyVersionMax) {
					$version ++;
				} else {
					$version = 1;
				}
				UtilD::setCache ( $key, $memkey, $version, 3600 );
			}
		}
		return true;
	}
	
	/*
	 * 将一个key保存到当前模型对象所对应的模型类在memcached中的key集合中
	 */
	public function saveKeyToMemKeySet($key) {
		$className = strtolower ( get_called_class () );
		$setKey = 'keyversion_' . $className;
		/*
		 * $keySet = UtilD::getCache ( $className, $setKey ); if($keySet &&
		 * is_array($keySet)){ $keySet[] = $key; } else{ $keySet = array($key);
		 * }
		 */
		$keySet = array ($key );
		return UtilD::setCache ( $className, $setKey, $keySet, 3600 );
	}
	
	public function removePageMem($key) {
		$className = strtolower ( get_called_class () );
		return UtilD::setCache ( $className, $key, '', 1 );
	}
	
	/*
	 * 判断是否需要做日志
	 */
	public function needLog() {
		/* 暂不记录日志
		 * $action = strtolower ( Yii::app ()->controller->getRoute () );
		if (! Yii::app ()->controller->logged && $action && Yii::app ()->backlog->filter ( $action )) {
			return true;
		}*/  
		return false;
	}
	
	/*
	 * 写日志
	 */
	public function logging($flag) {
		if ($this->needLog ()) {
			try {
				Yii::app ()->backlog->logging ( $this->logAttributes, $flag );
			} catch ( Exception $e ) {
				return false;
			}
			Yii::app ()->controller->logged = 1;
			return true;
		}
		return false;
	}
	
	/**
	 * 用于权限判断是否超链接
	 * 'url'=>'/admin/trend/update&' url必须为此形式
	 * 
	 * @author add by wc 2012-2-7
	 */
	public function getLinksByPermission($datas = array()) {
		$rlts = array ();
		if (is_string ( $datas )) {
			$beginIndex = strpos ( $datas, 'r=' ) + 2;
			if ($beginIndex == 2) {
				$beginIndex = strpos ( $datas, '/' ) + 1;
			}
			$route = substr ( $datas, $beginIndex );
			$endIndex = strpos ( $datas, '&' );
			if ($endIndex) {
				$length = $endIndex - $beginIndex;
				$route = substr ( $datas, $beginIndex, $length );
			}
			return UtilD::isPass ( $route );
		}
		if (is_array ( $datas )) {
			foreach ( $datas as $key => $data ) {
				$dump = $data;
				$beginIndex = strpos ( $data ['url'], '?r=' ) + 2;
				if ($beginIndex == 2) {
					$beginIndex = strpos ( $data ['url'], '/' ) + 1;
				}
				$route = substr ( $data ['url'], $beginIndex );
				$endIndex = strpos ( $data ['url'], '&' );
				if ($endIndex) {
					$length = $endIndex - $beginIndex;
					$route = substr ( $data ['url'], $beginIndex, $length );
				}
				
				if (UtilD::isPass ( $route )) {
					$url = Yii::app ()->createUrl ( $data ['url'] );
					$dump ['url'] = $url;
					$dump ['isPass'] = TRUE;
				} else {
					$dump ['isPass'] = FALSE;
				}
				$rlts [$key] = $dump;
			}
			// var_dump($rlts);exit;
			return $rlts;
		}
	}
}

?>